Best meeting point¶
Time: O(MxN); Space: O(M+N); hard
A group of two or more people wants to meet and minimize the total travel distance. You are given a 2D grid of values 0 or 1, where each 1 marks the home of someone in the group. The distance is calculated using Manhattan Distance, where distance(p1, p2) = |p2.x - p1.x| + |p2.y - p1.y|.
Example 1:
Input: grid =
[
[1, 0, 0, 0, 1],
[0, 0, 0, 0, 0],
[0, 0, 1, 0, 0]
]
Output: 6
Explanation:
Given three people living at (0,0), (0,4), and (2,2).
The point (0,2) is an ideal meeting point, as the total travel distance of 2+2+2=6 is minimal.
Thought Process¶
Brute Force
Try every point and calculate the 1’s distance to this point
The best distance can be found by using min function
Time complexity O(m2n2) Space complexity O(mn)
Sorting
The optimal point is at the mean. For example, 1-1-0-0-1, the optimal point is at x = 1, and assume the total distance is d
If we move the point to the right, x = 2, the total distance will be d + 2 - 1, since there will be two points on its left and 1 point on its right
For even number of 1’s, we can pick either one of middle as the choice, for example 1-1-0-0-1-1 Time complexity: O(MxN + MxNxLog(MxN)) = O(MxNxLog(MxN)) Space complexity: O(MxN)
Without Sorting
Write separate function for collecting rows and col Time complexity: O(MxN) Space complexity: O(MxN)
Two Pointers
We can modify the distance function to use two pointers, using highIndex - lowIndex Time complexity: O(MxN) Space complexity: O(MxN)
One pass with Count
We can modify the distance function to use frequency to find the reach the median Time complexity: O(MxN) Space complexity: O(MxN)
[7]:
from random import randint
class Solution1(object):
def minTotalDistance(self, grid):
"""
:type grid: List[List[int]]
:rtype: int
"""
x = [i for i, row in enumerate(grid) for v in row if v == 1]
y = [j for row in grid for j, v in enumerate(row) if v == 1]
mid_x = self.findKthLargest(x, len(x) // 2 + 1)
mid_y = self.findKthLargest(y, len(y) // 2 + 1)
return sum([abs(mid_x-i) + abs(mid_y-j) \
for i, row in enumerate(grid) for j, v in enumerate(row) if v == 1])
def findKthLargest(self, nums, k):
left, right = 0, len(nums) - 1
while left <= right:
pivot_idx = randint(left, right)
new_pivot_idx = self.PartitionAroundPivot(left, right, pivot_idx, nums)
if new_pivot_idx == k - 1:
return nums[new_pivot_idx]
elif new_pivot_idx > k - 1:
right = new_pivot_idx - 1
else: # new_pivot_idx < k - 1.
left = new_pivot_idx + 1
def PartitionAroundPivot(self, left, right, pivot_idx, nums):
pivot_value = nums[pivot_idx]
new_pivot_idx = left
nums[pivot_idx], nums[right] = nums[right], nums[pivot_idx]
for i in range(left, right):
if nums[i] > pivot_value:
nums[i], nums[new_pivot_idx] = nums[new_pivot_idx], nums[i]
new_pivot_idx += 1
nums[right], nums[new_pivot_idx] = nums[new_pivot_idx], nums[right]
return new_pivot_idx
[9]:
s = Solution1()
grid = [[1, 0, 0, 0, 1],
[0, 0, 0, 0, 0],
[0, 0, 1, 0, 0]
]
assert s.minTotalDistance(grid) == 6